package com.ucar.notice.notice.service.impl;

import com.ucar.base.alarminfo.alarm.AlarminfoRewriteNoticeDTO;
import com.ucar.base.intrdriver.notice.common.DriverNoticeConstants.NoticeTypeEnum;
import com.ucar.base.intrdriver.notice.dto.DriverQueryDTO;
import com.ucar.base.vo.OpResult;
import com.ucar.common.constant.RedisConstant;
import com.ucar.log.HbaseLogUtil;
import com.ucar.log.LogEnum;
import com.ucar.notice.notice.dao.NoticeConfigDao;
import com.ucar.notice.notice.dao.NoticeDao;
import com.ucar.notice.notice.handler.AbstractNoticeIssueProcessor;
import com.ucar.notice.notice.handler.NoticeIssueProcessor;
import com.ucar.notice.notice.handler.callback.IssueProcessCallback;
import com.ucar.notice.notice.handler.callback.InvokeMessageCallback;
import com.ucar.notice.notice.pojo.NoticeBean;
import com.ucar.notice.notice.pojo.NoticeConfigBean;
import com.ucar.notice.notice.service.NoticeIssueService;
import com.ucar.notice.send.service.NoticeSendService;
import com.ucar.notice.util.MqSendUtil;
import com.ucar.util.StringTools;
import com.ucar.util.TimeOuter;
import com.zuche.framework.threadPool.CommonThreadPool;
import com.zuche.framework.threadPool.IAsynchronousHandler;
import com.zuche.redis.core.HashCommands;
import com.zuche.redis.factory.RedisFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.LinkedList;
import java.util.List;

/**
 * Description:通知下发接口实现类 
 * All Rights Reserved.
 * @version 1.0  2016-3-27 下午5:05:26  by 石冬冬-Chris Suk（dd.shi02@zuche.com）创建
 */
@Service
public class NoticeIssueServiceImpl implements NoticeIssueService {
	private static Logger logger = LoggerFactory.getLogger(NoticeIssueServiceImpl.class);
	private final HashCommands HASH_CMD = RedisFactory.getClusterHashCommands(RedisConstant.DEFAULT_REDIS_GROUP_NAME);
	@Autowired
	private NoticeDao noticeDao;
	@Autowired
	private NoticeConfigDao noticeConfigDao;
	@Autowired
	private NoticeSendService noticeSendService;
	@Autowired
	private NoticeIssueProcessor noticeIssueProcessor;

	@Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRES_NEW)
	@Override
	public OpResult<String> issueForSingle(final String ids) {
		return this.noticeIssueProcessor.handle(new IssueProcessCallback() {
			@Override
			public List<NoticeBean> queryList() {
				return noticeDao.getListByIds(ids);
			}

			@Override
			public InvokeMessageCallback call() {
				return new InvokeMessageCallback() {
					@Override
					public boolean needCheck() {
						return true;
					}
					@Override
					public boolean allowIssueWhenUnvalid() {return false;}
					@Override
					public String call(AbstractNoticeIssueProcessor baseProcessor) {
						StringBuilder message = new StringBuilder();
						NoticeIssueProcessor processor = (NoticeIssueProcessor)baseProcessor;
						if(processor.getNotRequiredList().size() > 0){
							message.append("下发失败，原因：所选通知状态为已下发或已删除");
						}
						if(processor.getNoDriverList().size() > 0){
							message.append("该通知没有指定司机，请确认。");
						}
						return message.toString();
					}
				};
			}
		});
	}

	@Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRES_NEW)
	@Override
	public OpResult<String> issueForBatch(final String ids) {
		return this.noticeIssueProcessor.handle(new IssueProcessCallback() {
			@Override
			public List<NoticeBean> queryList() {
				return noticeDao.getListByIds(ids);
			}

			@Override
			public InvokeMessageCallback call() {
				return new InvokeMessageCallback() {
					@Override
					public boolean needCheck() {
						return true;
					}
					@Override
					public boolean allowIssueWhenUnvalid() {return true;}
					@Override
					public String call(AbstractNoticeIssueProcessor baseProcessor) {
						StringBuilder message = new StringBuilder();
						NoticeIssueProcessor processor = (NoticeIssueProcessor)baseProcessor;
						if(CollectionUtils.isEmpty(processor.getNoticeList())){
							message.append("下发失败，原因：所选通知状态为已下发或已删除，或者没有指定司机");
						}else{
							if(processor.getNotRequiredList().size() > 0){
								message.append("选中数据中存在状态为已下发或已删除的通知，该部分通知下发失败。");
							}
							if(processor.getNoDriverList().size() > 0){
								message.append("选中数据中存在没有指定司机的通知，该部分通知下发失败。");
							}
						}
						return message.toString();
					}
				};
			}
		});
	}

	@Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRES_NEW)
	@Override
	public OpResult<String> issueForSchedule(final String ids) {
		return this.noticeIssueProcessor.handle(new IssueProcessCallback() {
			@Override
			public List<NoticeBean> queryList() {
				return noticeDao.getListByIds(ids);
			}

			@Override
			public InvokeMessageCallback call() {
				return new InvokeMessageCallback() {
					@Override
					public boolean needCheck() {
						return false;
					}
					@Override
					public boolean allowIssueWhenUnvalid() {return true;}
					@Override
					public String call(AbstractNoticeIssueProcessor baseProcessor) {
						return null;
					}
				};
			}
		});
	}

	@Override
	public boolean execute(final List<NoticeBean> noticeList){
		boolean flag = true;
		CommonThreadPool.execute( new IAsynchronousHandler( ) {
			@Override
			public Object call() throws Exception {
				try {
					final long start = System.currentTimeMillis();
					StringBuilder sb = new StringBuilder();
					if(CollectionUtils.isNotEmpty(noticeList)){
						for(NoticeBean noticeBean : noticeList){
							Integer noticeType = noticeBean.getNoticeType();
							Integer driverType = noticeBean.getDriverType();
							Long noticeId = noticeBean.getId();
							sb.append(noticeId).append(StringTools.SYMBOL_SPLITOR);
							AlarminfoRewriteNoticeDTO noticeMQSendDto = noticeDao.getNoticeContentById(noticeId);
							DriverQueryDTO driverQueryDTO = new DriverQueryDTO();
							NoticeTypeEnum noticeTypeEnum = NoticeTypeEnum.getByIndex(noticeType);
							//全员通知
							if(NoticeTypeEnum.ALL_NOTICE == noticeTypeEnum){
								driverQueryDTO.setDriverType(driverType);
							}
							//大区通知、城市通知
							if(NoticeTypeEnum.REGION_NOTICE == noticeTypeEnum||NoticeTypeEnum.CITY_NOTICE == noticeTypeEnum){
								List<Long> cityIdList = getIdList(noticeId, new SetIdCallback(){
									@Override
									public void setId(final List<Long> ids, NoticeConfigBean noticeConfigBean) {
										ids.add(noticeConfigBean.getCityId());
									}
								});
								if(CollectionUtils.isNotEmpty(cityIdList)){
									driverQueryDTO.setDriverType(driverType);
									driverQueryDTO.setScope(StringUtils.join(cityIdList, StringTools.SYMBOL_SPLITOR));
								}
								noticeMQSendDto.setCityIds(cityIdList);
							}
							//部分通知
							if(NoticeTypeEnum.PART_NOTICE == noticeTypeEnum){
								List<Long> driverIdList = getIdList(noticeId, new SetIdCallback(){
									@Override
									public void setId(final List<Long> ids, NoticeConfigBean noticeConfigBean) {
										ids.add(noticeConfigBean.getDriverId());
									}
								});
								if(CollectionUtils.isNotEmpty(driverIdList)){
									driverQueryDTO.setDriverType(driverType);
									driverQueryDTO.setIds(StringUtils.join(driverIdList, StringTools.SYMBOL_SPLITOR));
								}
								noticeMQSendDto.setDriverIds(driverIdList);
							}
							//插入下发表
							noticeSendService.send(HASH_CMD, RedisConstant.RedisLifeStrategyEnum.REPLACE,noticeBean, driverQueryDTO);
							//调用发送MQ，写入司机系统老库
							MqSendUtil.sendAlarmInfoRewriteMq(noticeMQSendDto);
						}
					}
					String outDriverIds = StringTools.removeLastSymb(sb.toString());
					HbaseLogUtil.sendHbaseLogMQ(0L, LogEnum.Alarminfo.LogTypeEnum.NOTICE_ISSUE, "【司机通知下发】通知下发", null, noticeList,outDriverIds);
					logger.info(TimeOuter.format(System.currentTimeMillis()-start, "【司机通知-下发】,通知共计={}条,通知ids={}"),noticeList.size(),StringTools.truncate(outDriverIds, StringTools.MAX_LENGTH));
				} catch (Exception e) {
					HbaseLogUtil.sendHbaseLogMQ(0L, LogEnum.Alarminfo.LogTypeEnum.NOTICE_ISSUE, "【司机通知下发】通知下发异常", e, noticeList);
					logger.error("【司机通知-下发】异常",e);
				}
				return null;
			}
			@Override
			public void executeBefore(Thread arg0) {}
			@Override
			public void executeAfter(Throwable arg0) {}
		});
		return flag;
	}

	/**
	 * Description:  获取 对应的ID列表
	 * @param noticeId
	 * @param setIdCallback
	 * @return
	 * @version 1.0 2016年3月25日 下午6:16:26 created by 张淑峰(sf.zhang02@zuche.com)
	 */
	private List<Long>  getIdList(Long noticeId,SetIdCallback setIdCallback){
		 List<NoticeConfigBean>  configList = this.noticeConfigDao.queryAllByNoticeId(noticeId);
		 if (CollectionUtils.isNotEmpty(configList)) {
			List<Long> idList = new LinkedList<Long>();
			for (NoticeConfigBean configBean : configList) {
				if (configBean != null ) {
					setIdCallback.setId(idList, configBean);
				}
			}
			return idList;
		}
		return null;
	}

	/**
	 * Description:
	 * All Rights Reserved.
	 * @version 1.0 2016年3月26日 上午10:25:35 created by 张淑峰(sf.zhang02@zuche.com)
	 */
	private interface  SetIdCallback{
		void setId(final List<Long> idList, NoticeConfigBean noticeConfigBean);
	}
}
